﻿package zf.data.geom
{
	import flash.geom.Point;

	/**
	 * 几何公式类，提供一些常用公式的算法,对原来Math类进行有效补充。
	 * <br />很多时候你需要结合Math使用 
	 * @author Mike.zhang
	 * 
	 */

	public class Formula
	{
		/**
		 * @private 
		 * 
		 */
		public function Formula ()
		{
			throw new ArgumentError("无法实例化 Formula 类",2012);
		}
		/**
		 * 计算两个坐标间的距离
		 * @param x 坐标1的x
		 * @param y 坐标1的y
		 * @param dx 坐标2的x
		 * @param dy 坐标2的y
		 * @return 距离
		 * 
		 */
		public static  function distance (x:Number,y:Number,dx:Number,dy:Number):Number
		{
			var xx:Number=x - dx;
			var yy:Number=y - dy;
			return Math.sqrt(xx * xx + yy * yy);
		}
		/**
		 * 计算两个坐标间的距离的平方
		 * @param x 坐标1的x
		 * @param y 坐标1的y
		 * @param dx 坐标2的x
		 * @param dy 坐标2的y
		 * @return 距离的平方
		 * 
		 */
		public static function distanceSq(x:Number,y:Number,dx:Number,dy:Number):Number
		{
			var xx:Number=x - dx;
			var yy:Number=y - dy;
			return xx * xx + yy * yy;
		}
		/**
		 * 将弧度r转化成角度 
		 * @param r 要转化的弧度
		 * @return 角度
		 * @see #angleToRadian()
		 * @example 下面计算180度的弧度
		 * <listing version="3.0">Formula.radianToAngle(180) //3.1415926</listing>
		 * 
		 */
		public static  function radianToAngle (r:Number):Number
		{
			return r * 180 / Math.PI;
		}
		/**
		 * 将角度a转化成弧度 
		 * @param a 要转化的角度
		 * @return 弧度
		 * @see #radianToAngle()
		 * @example 下面计算PI弧度的角度
		 * <listing version="3.0">Formula.angleToRadian(Math.PI) //180</listing>
		 */
		public static  function angleToRadian (a:Number):Number
		{
			return a * Math.PI / 180;
		}
		/**
		 * 将任意角度a转化为0-->360之间的角度
		 * @param a 要转化的角度
		 * @return 0-->360之间的角度
		 * 
		 */
		public static  function angleTo360 (a:Number):Number
		{
			var p:uint;
			if (a < 0)
			{
				p=Math.ceil(- a / 360) * 360;
				return p + a;
			}
			p=Math.floor(a / 360) * 360;
			return a - p;
		}
		/**
		 * 将任意角度a转化为-180-->180之间的角度
		 * @param a 要转化的角度
		 * @return -180-->180之间的角度
		 * 
		 */
		public static  function angleTo180 (a:Number):Number
		{
			a=angleTo360(a);
			if (a > 180)
			{
				return a - 360;
			}
			return a;
		}
		/**
		 * 返回角度a到角度b的绝对值最小角度。
		 * <br />用于在圆周上移动，从圆周上某点到该圆周上下一点寻找最小扇形的圆心角。
		 * @param a 起始角度
		 * @param b 目标角度
		 * @return -180-->180之间的一个角度值
		 * 
		 */
		public static  function minAngle (a:Number,b:Number):Number
		{
			a=angleTo180(a);
			b=angleTo180(b);
			var p:Number=a - b;
			var c:Number;
			if (p <= -180)
			{
				c=-360 - p;
			}
			else if (p <= 180)
			{
				c=- p;
			}
			else
			{
				c=360 - p;
			}
			return c;
		}
		/**
		 * 一元二次方程求解。
		 * a x^2 + b x + c = 0
		 * 如果存在，返回一元二次方程的解，否则返回null 
		 * @param a a值
		 * @param b b值
		 * @param c c值
		 * @return 如有有解返回数组，数组每个元素为一个解，否组返回null
		 * 
		 */
		public static  function equation1_2 (a:Number,b:Number,c:Number):Array
		{
			if (a == 0)
			{
				return null;
			}
			var num:Number=b * b - 4 * a * c;
			if (num >= 0)
			{
				var x1:Number;
				if (num == 0)
				{
					x1=- b * 0.5 / a;
					return new Array(x1);
				}
				else
				{
					var x2:Number;
					num=Math.sqrt(num);
					x1=- b + num * 0.5 / a;
					x2=- b - num * 0.5 / a;
					return new Array(x1,x2);
				}
			}
			return null;
		}
		/**
		 * 将点 p 依 cp 旋转 radian 弧度所成的点
		 * @param p 待旋转的点
		 * @param radian 旋转弧度
		 * @param cp 旋转的参考点
		 * @return 旋转后的点
		 * 
		 */
		public static  function turnPoint (p:Point,radian:Number,cp:Point=null):Point
		{
			//(x,y)绕任一点（x0，y0）的旋转θ角变换公式为
			//x’=xcos(θ )- ysin(θ) - x0cos(θ)+y0sin(θ)+x0

			//y’=xsin(θ)+ycos(θ) - x0sin(θ) - y0cos(θ)+y0
			if (p == null)
			{
				return null;
			}
			if (cp == null)
			{
				cp=new Point  ;
			}
			var sa:Number=Math.sin(radian);
			var ca:Number=Math.cos(radian);

			var dx:Number=p.x * ca - p.y * sa - cp.x * ca + cp.y * sa + cp.x;
			var dy:Number=p.x * sa + p.y * ca - cp.x * sa - cp.y * ca + cp.y;

			return new Point(dx,dy);
		}
		/**
		 * 坐标系变换求点。用于将求原坐标系中点p在新坐标系(原坐标系旋转平移得到新坐标系)中的对应点 
		 * @param p 原坐标系中点
		 * @param radian 新坐标系的旋转弧度
		 * @param cp 新坐标系原点所在位置
		 * @return 变换坐标系后对应点
		 * @see #obTransformPoint()
		 *  @example 下面计算点（3，4）在新坐标系（原坐标系移动（1，1）旋转 Math.PI*0.25 弧度即45度）中成的点。
		 * 然后再求新点在原坐标系中的点
		 * <listing version="3.0">
		 * import flash.geom.Point;
		 * 
		 * var p:Point=new Point(3,4);
		 * var c:Point=new Point(1,1);
		 * var n:Number=Math.PI*0.25;
		 * 
		 * var p0:Point=Formula.transformPoint(p,n,c);//(x=3, y=-1.9999999999999996)
		 * var p1:Point=Formula.obTransformPoint(p0,n,c); //(3,4)   
		 * </listing>
		 */
		public static  function transformPoint (p:Point,radian:Number,cp:Point=null):Point
		{
			//设平面上任一点关于旧系{O；i，j}与新系{O′；i′，j′}的坐标分别为（x,y）
			//（x′，y′），关于{O′；i，j}的坐标为（x″，y″），而O′在{O；i，j}下的坐标为（a,b），则

			//x'=x cos(θ) + y sin(θ) - a cos(θ) - b sin(θ)
			//y'=-x sin(θ) + y cos(θ) + a sin(θ) - b cos(θ)
			if (p == null)
			{
				return null;
			}
			if (cp == null)
			{
				cp=new Point  ;
			}
			var sa:Number=Math.sin(radian);
			var ca:Number=Math.cos(radian);

			var dx:Number=p.x * ca + p.y * sa - cp.x * ca - cp.y * sa;
			var dy:Number=- p.x * sa + p.y * ca + cp.x * sa - cp.y * ca;

			return new Point(dx,dy);

		}
		/**
		 * 坐标系变换求点。用于将求新坐标系中点p在原坐标系(原坐标系旋转平移得到新坐标系)中的对应点 
		 * @param p 新坐标系中点
		 * @param radian 新坐标系的旋转弧度
		 * @param cp 新坐标系原点所在位置
		 * @return 原坐标系对应点
		 * @see #transformPoint()
		 * @example 下面计算点（3，4）在新坐标系（原坐标系移动（1，1）旋转 Math.PI*0.25 弧度即45度）中成的点。
		 * 然后再求新点在原坐标系中的点
		 * <listing version="3.0">
		 * import flash.geom.Point;
		 * 
		 * var p:Point=new Point(3,4);
		 * var c:Point=new Point(1,1);
		 * var n:Number=Math.PI*0.25;
		 * 
		 * var p0:Point=Formula.transformPoint(p,n,c);//(x=3, y=-1.9999999999999996)
		 * var p1:Point=Formula.obTransformPoint(p0,n,c); //(3,4)   
		 * </listing>
		 */
		public static  function obTransformPoint (p:Point,radian:Number,cp:Point=null):Point
		{
			//设平面上任一点关于旧系{O；i，j}与新系{O′；i′，j′}的坐标分别为（x,y）
			//（x′，y′），关于{O′；i，j}的坐标为（x″，y″），而O′在{O；i，j}下的坐标为（a,b），则

			//x=x' cos(θ) - y' sin(θ) + a
			//y=x' sin(θ) + y cos(θ) + b
			if (p == null)
			{
				return null;
			}
			if (cp == null)
			{
				cp=new Point  ;
			}
			var sa:Number=Math.sin(radian);
			var ca:Number=Math.cos(radian);

			var dx:Number=p.x * ca - p.y * sa + cp.x;
			var dy:Number=p.x * sa + p.y * ca + cp.y;

			return new Point(dx,dy);

		}
	}
}